package social.hub.twitter;

import java.util.List;
import java.util.Map;

import social.hub.util.UrlBuilder;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.json.JSONConfiguration;
import com.sun.jersey.oauth.client.OAuthClientFilter;
import com.sun.jersey.oauth.signature.OAuthParameters;
import com.sun.jersey.oauth.signature.OAuthSecrets;

/**
 * http://dev.twitter.com/doc
 * 
 * @author Andre
 */
public class TwitterClientImpl implements TwitterClient {

	private static final String API_URL_BASE = "https://api.twitter.com/1/";

	private static final String VERIFY_CREDENTIALS_URL = API_URL_BASE
			+ "account/verify_credentials.{format}";

	private static final String USER_SHOW_URL = API_URL_BASE + "users/show.{format}";
	private static final String USER_SUGGESTIONS_URL = API_URL_BASE + "users/suggestions.{format}";
	private static final String USER_LOOKUP_URL = API_URL_BASE + "users/lookup.{format}";
	private static final String USER_SEARCH_URL = API_URL_BASE + "users/search.{format}";
	private static final String USER_SUGGESTIONS_CATEGORY_URL = API_URL_BASE
			+ "users/suggestions/slug.{format}";

	private static final String DIRECT_MESSAGES_URL = API_URL_BASE + "direct_messages.{format}";
	private static final String DIRECT_MESSAGES_SENT_URL = API_URL_BASE
			+ "direct_messages/sent.{format}";
	private static final String DIRECT_MESSAGE_SEND_URL = API_URL_BASE
			+ "direct_messages/new.{format}";
	private static final String DIRECT_MESSAGE_DESTROY_URL = API_URL_BASE
			+ "direct_messages/destroy/id.{format}";

	private static final String SEARCH_API_URL_BASE = "https://search.twitter.com";
	private static final String SEARCH_URL = SEARCH_API_URL_BASE
			+ "/search.json?q={query}&rpp={rpp}&page={page}";

	private static final String STATUSES_SHOW_URL = API_URL_BASE
			+ "statuses/show/{tweet_id}.{format}";
	private static final String STATUSES_UPDATE_URL = API_URL_BASE + "statuses/update.{format}";
	private static final String STATUSES_DESTROY_URL = API_URL_BASE
			+ "statuses/destroy/{tweet_id}.{format}";
	private static final String STATUSES_FRIENDS_URL = API_URL_BASE + "statuses/friends.{format}";
	private static final String STATUSES_FOLLOWERS_URL = API_URL_BASE
			+ "statuses/followers.{format}";
	private static final String STATUSES_RETWEET_URL = API_URL_BASE
			+ "statuses/retweet/{tweet_id}.{format}";
	private static final String STATUSES_RETWEETS_URL = API_URL_BASE
			+ "statuses/retweets/{tweet_id}.{format}";
	private static final String STATUSES_RETWEETED_BY_URL = API_URL_BASE
			+ "statuses/{tweet_id}/retweeted_by.{format}";
	private static final String STATUSES_RETWEETED_BY_IDS_URL = API_URL_BASE
			+ "statuses/{tweet_id}/retweeted_by/ids.{format}";

	private static final String PUBLIC_TIMELINE_URL = API_URL_BASE
			+ "statuses/public_timeline.{format}";
	private static final String HOME_TIMELINE_URL = API_URL_BASE
			+ "statuses/home_timeline.{format}";
	private static final String FRIENDS_TIMELINE_URL = API_URL_BASE
			+ "statuses/friends_timeline.{format}";
	private static final String USER_TIMELINE_URL = API_URL_BASE
			+ "statuses/user_timeline.{format}";

	private static final GenericType<Map<String, Object>> MAP_TYPE = new GenericType<Map<String, Object>>() {
	};

	private static final GenericType<List<TwitterProfile>> TWITTER_PROFILE_LIST_TYPE = new GenericType<List<TwitterProfile>>() {
	};

	private static final GenericType<List<Tweet>> TWEET_LIST_TYPE = new GenericType<List<Tweet>>() {
	};

	private Client client;

	public TwitterClientImpl(String consumerToken, String consumerTokenSecret, String accessToken,
			String accessTokenSecret) {

		ClientConfig clientConfig = new DefaultClientConfig();
		clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);

		client = Client.create(clientConfig);

		OAuthParameters oauthParameters = new OAuthParameters().consumerKey(consumerToken).token(
				accessToken);
		OAuthSecrets oauthSecrets = new OAuthSecrets().consumerSecret(consumerTokenSecret)
				.tokenSecret(accessTokenSecret);

		OAuthClientFilter filter = new OAuthClientFilter(client.getProviders(), oauthParameters,
				oauthSecrets);

		client.addFilter(filter);

	}

	@Override
	public List<TwitterProfile> getFollowers() {
		return getFollowers(getUserId());
	}

	@Override
	public List<TwitterProfile> getFollowers(Long twitterId) {
		String url = new UrlBuilder(STATUSES_FOLLOWERS_URL).addUrlParan("format", "json")
				.addQueryParan("user_id", twitterId).toString();
		return client.resource(url).get(TWITTER_PROFILE_LIST_TYPE);
	}

	@Override
	public List<TwitterProfile> getFriends() {
		return getFriends(getUserId());
	}

	@Override
	public List<TwitterProfile> getFriends(Long twitterId) {
		String url = new UrlBuilder(STATUSES_FRIENDS_URL).addUrlParan("format", "json")
				.addQueryParan("user_id", twitterId).toString();
		return client.resource(url).get(TWITTER_PROFILE_LIST_TYPE);
	}

	@Override
	public List<Tweet> getFriendsTimeline() {
		String url = new UrlBuilder(FRIENDS_TIMELINE_URL).addUrlParan("format", "json")
				.addQueryParan("user_id", getUserId()).toString();
		return client.resource(url).get(TWEET_LIST_TYPE);
	}

	@Override
	public List<Tweet> getHomeTimeline() {
		String url = new UrlBuilder(HOME_TIMELINE_URL).addUrlParan("format", "json")
				.addQueryParan("user_id", getUserId()).toString();
		return client.resource(url).get(TWEET_LIST_TYPE);
	}

	@Override
	public List<Tweet> getPublicTimeline() {
		String url = new UrlBuilder(PUBLIC_TIMELINE_URL).addUrlParan("format", "json")
				.addQueryParan("user_id", getUserId()).toString();
		return client.resource(url).get(TWEET_LIST_TYPE);
	}

	@Override
	public Long getUserId() {
		String url = new UrlBuilder(VERIFY_CREDENTIALS_URL).addUrlParan("format", "json")
				.toString();
		Map<String, Object> response = client.resource(url).get(MAP_TYPE);
		return Long.valueOf(response.get("id_str").toString());
	}

	@Override
	public TwitterProfile getUserProfile() {
		return getUserProfile(getUserId());
	}

	@Override
	public TwitterProfile getUserProfile(Long twitterId) {
		String url = new UrlBuilder(USER_SHOW_URL).addUrlParan("format", "json")
				.addQueryParan("user_id", twitterId).toString();
		return client.resource(url).get(TwitterProfile.class);
	}

	@Override
	public List<Tweet> getUserTimeline() {
		return getUserTimeline(getUserId());
	}

	@Override
	public List<Tweet> getUserTimeline(Long twitterId) {
		String url = new UrlBuilder(USER_TIMELINE_URL).addUrlParan("format", "json")
				.addQueryParan("user_id", twitterId).toString();
		return client.resource(url).get(TWEET_LIST_TYPE);
	}

	@Override
	public void retweet(long tweetId) {
		String url = new UrlBuilder(STATUSES_RETWEET_URL).addUrlParan("format", "json")
				.addQueryParan("tweet_id", tweetId).toString();
		client.resource(url).post();

	}

	@Override
	public void sendDirectMessage(String text, String toTwitterId) {
		String url = new UrlBuilder(DIRECT_MESSAGE_SEND_URL).addUrlParan("format", "json")
				.addQueryParan("user_id", toTwitterId).addQueryParan("text", text).toString();
		client.resource(url).post();
	}

	@Override
	public void updateStatus(String status) {
		String url = new UrlBuilder(STATUSES_UPDATE_URL).addUrlParan("format", "json")
				.addQueryParan("status", status).toString();
		client.resource(url).post();

	}

}
